﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Lon.Util;


namespace Lon.Server
{
    public class DataFrame
    {
        private DataFrameFlag dataFrameFlag;

        public DataFrameFlag DataFrameFlag
        {
            get { return dataFrameFlag; }
        }

        private string srcDbm;

        private int srcId;

        public int SrcId
        {
            get
            { return srcId; }
            set
            {
                srcId = value;
                this.srcDbm = Int2DBM(this.srcId);
                SetId(8, value);
            }
        }

        private void SetId(int index, int value)
        {
            if ((index + 3) > this.buf.Length) return;
            this.buf[index] = (byte)(value & 0xff);
            this.buf[index + 1] = (byte)((value >> 8) & 0xff);
            this.buf[index + 2] = (byte)((value >> 16) & 0xff);
        }
        private int GetId(int index)
        {
            if ((index + 3) > this.buf.Length) return 0;
            int ret = this.buf[index];
            ret += (this.Buf[index + 1]) << 8;
            ret += (this.Buf[index + 2] << 16);
            return ret;
        }

        private int dstId;

        public int DstId
        {
            get { return dstId; }
            set
            {
                dstId = value;
             
                this.dstDbm = Int2DBM(this.dstId);
                SetId(5, value);
            }
        }

        public string SrcDbm
        {
            get { return srcDbm; }
            set
            {
                this.srcDbm = value;
                SetDbm(8, value);

            }

        }

        private string dstDbm;

        public string DstDbm
        {
            get { return dstDbm; }
            set
            {
                this.srcDbm = value;
                SetDbm(5, value);
            }
        }

        public bool IsCommand { get; private set; }


        public bool IsCompress { get; private set; }

        private string GetDbm(int startIndex)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                for (int i = startIndex; i < startIndex + 3; i++)
                {
                    char c = (char)(this.buf[i]);
                    if (c > 0x80) c -= (char)0x80;
                    sb.Append(c);
                }
                return sb.ToString();

            }
            catch
            {
                return String.Empty;
            }
        }

        public static string GetDbm(int startIndex, byte[] dataBuf)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                for (int i = startIndex; i < startIndex + 3; i++)
                {
                    char c = (char)(dataBuf[i]);
                    if (c > 0x80) c -= (char)0x80;
                    sb.Append(c);
                }
                return sb.ToString();

            }
            catch
            {
                return String.Empty;
            }
        }

        private void SetDbm(int index, string value)
        {
            System.Text.Encoding.ASCII.GetBytes(value, 0, 3, this.buf, index);
        }
        private DataDir dataDir;

        public DataDir DataDir
        {
            get
            {
                return dataDir;

            }
            set
            {
                this.dataDir = value;
                this.buf[13] = (byte)value;
            }
        }

        private MajorDataType majorDataType;
        public MajorDataType MajorDataType
        {
            get
            {
                return majorDataType;

            }
            set
            {
                this.majorDataType = value;
                buf[14] = (byte)value;
            }
        }
        public byte MinorDataType
        {
            get;
            set;

        }
        const int DataStartIndex = 16;
        public TransType GetTransType()
        {
            try
            {
                if (DataFrameFlag != DataFrameFlag.Data) return TransType.DisableTrans;
                if (DataDir == DataDir.StationData)
                {
                    if (MajorDataType == MajorDataType.KglRealValue) return TransType.ToConnectedClient;
                    if (MajorDataType == MajorDataType.SystemState) return TransType.ToConnectedClient;
                    //  if (MajorDataType == MajorDataType.KglRealValue) return TransType.ToAllClient;
                    //  if (MajorDataType == MajorDataType.SystemState) return TransType.ToAllClient;
                    if (MajorDataType == MajorDataType.Alarm) return TransType.ToAllClientAndAck;
                    if (MajorDataType == MajorDataType.PrivateFeature && this.buf[DataStartIndex + 0] == (int)MajorDataType.KglRealValue) return TransType.ToConnectedClient;
                    //   if (MajorDataType == MajorDataType.PrivateFeature && this.DataBuf[DataStartIndex + 0] == (int)MajorDataType.KglRealValue) return TransType.ToConnectedClient;
                }


            }
            catch { }
            return TransType.DisableTrans;
        }
        private byte[] buf;

        public byte[] Buf
        {
            get { return buf; }
        }
        private int maxCount = 0;

        public int MaxCount
        {
            get { return maxCount; }
        }


        public bool IsLonSelfFrame
        {
            get;
            set;
        }

        public DataFrame(byte[] buf)
        {

            if (buf.Length < 16)
            {
                this.dataFrameFlag = DataFrameFlag.UnKnow;
            }
            else this.dataFrameFlag = (DataFrameFlag)buf[4];
            this.buf = buf;
            this.maxCount = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24) + 4;
            if (this.dataFrameFlag == DataFrameFlag.Data)
            {
                InitDataFrameParam(false);
            }

        }
        public DataFrame(byte[] buf,bool unZip)
        {

            if (buf.Length < 16)
            {
                this.dataFrameFlag = DataFrameFlag.UnKnow;
            }
            else this.dataFrameFlag = (DataFrameFlag)buf[4];
            this.buf = buf;
            this.maxCount = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24) + 4;
            if (this.dataFrameFlag == DataFrameFlag.Data)
            {
                InitDataFrameParam(unZip);
            }

        }

        private void InitDataFrameParam(bool unZip)
        {
            MemoryStream ms = new MemoryStream(this.buf);
            BinaryReader br = new BinaryReader(ms);
            int dataLength = br.ReadInt32();

            this.dstDbm = GetDbm(5);
            this.srcDbm = GetDbm(8);
            this.dstId = GetId(5);
            this.srcId = GetId(8);
            if (this.buf[11] == 0x01) this.IsCommand = true;
            else this.IsCommand = false;

            if (!this.IsCommand)
            {
                if (this.buf[12] == 0x01) this.IsCompress = true;
                else this.IsCompress = false;
                this.dataDir = (DataDir)buf[13];
                this.majorDataType = (MajorDataType)buf[14];
                this.MinorDataType = buf[15];
               
                if (this.MajorDataType == MajorDataType.PrivateFeature)
                {
                    this.IsLonSelfFrame = true;
                    this.majorDataType = (MajorDataType)buf[16];
                    this.MinorDataType = buf[17];
                    
                    ms.Seek(18, SeekOrigin.Begin);
                   
                }
                else
                {
                    ms.Seek(16, SeekOrigin.Begin);

                }
                if (this.MajorDataType == MajorDataType.NetStatus)
                {
                    ms.Seek(-1, SeekOrigin.Current);
                }
                byte[] tempBuf = br.ReadBytes((int)(buf.Length - 1 - ms.Position));
              
                if (unZip && this.IsCompress)
                {
                    this.DataBuf = ZipHelper.UnComPression(tempBuf, 0, tempBuf.Length);
                }
                else
                {
                    this.DataBuf = tempBuf;
                }
                
             
              
            }
            else
            {
                this.IsCompress = false;
                this.dataDir = (DataDir)buf[12];
                this.majorDataType = (MajorDataType)buf[13];
                this.MinorDataType = buf[14];


                if (this.MajorDataType == MajorDataType.PrivateFeature)
                {
                    this.IsLonSelfFrame = true;
                    this.majorDataType = (MajorDataType)buf[15];
                    this.MinorDataType = buf[16];
                    ms.Seek(17, SeekOrigin.Begin);
                }
                else
                {
                    ms.Seek(15, SeekOrigin.Begin);

                }
                if (this.majorDataType == MajorDataType.NetStatus)
                {
                    ms.Seek(-1, SeekOrigin.Current);
                }
                this.DataBuf = br.ReadBytes((int)(buf.Length - 1 - ms.Position));
            }


        }

        public DataFrame Clone()
        {
            return new DataFrame((byte[])this.Buf.Clone());
        }

        private static byte[] HeartbeatData = new byte[] { 0x0B, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
        public static byte[] GetHeartbeat()
        {
            //心跳帧
            return HeartbeatData;
        }

        byte[] dataBuf;
        public byte[] DataBuf
        {
            get
            {
                return dataBuf;
            }
            set
            {
                dataBuf = value;
            }
        }


        public DataFrame(int dstId, int srcId,
                            DataDir dir, bool isCompress,
                            bool isCmd, bool isLonSelf,
                            byte mType, byte minorDataType, byte[] dataBuf)
        {
            this.dataBuf = dataBuf;
            byte[] zipedBuf;
            this.IsLonSelfFrame = isLonSelf;
            int len;
            if (isLonSelf)
            {
                len = dataBuf.Length + 19;
            }
            else
            {
                len = dataBuf.Length + 17;
            }
            if (mType == 0x23)
            {
                len -= 1;
            }
            this.buf = new byte[len];
            this.dstId = dstId;
            this.srcId = srcId;
            this.srcDbm = Int2DBM(this.srcId);
            this.dstDbm = Int2DBM(this.dstId);
            this.dataDir = dir;
            this.majorDataType = (MajorDataType)mType;
            this.MinorDataType = minorDataType;
            this.IsCompress = isCompress;
            this.IsCommand = isCmd;
            MemoryStream ms = new MemoryStream(this.buf);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write(len - 5);
            bw.Write((byte)0x8f);
            bw.Write(this.dstId);
            ms.Seek(-1, SeekOrigin.Current);
            bw.Write(this.srcId);
            ms.Seek(-1, SeekOrigin.Current);
            bw.Write(this.IsCommand ? ((byte)1) : ((byte)0));
            if (!this.IsCommand)
            {
                bw.Write(this.IsCompress ? ((byte)1) : ((byte)0));
            }

            bw.Write((byte)dir);

            if (this.IsLonSelfFrame)
            {
                bw.Write((byte)0x40);
                bw.Write((byte)6);
            }
            bw.Write(mType);
            if (mType != 0x23)
            { 
                bw.Write(this.MinorDataType);
            }
           
            bw.Write(this.DataBuf);
            bw.Write((byte)0xff);

        }
        public string Int2DBM(int id)
        {
            int i;
            StringBuilder sb = new StringBuilder(5);
            for (i = 0; i < 4; i++)
            {
                char ch = (char)(id & 0x7f);
                id = id >> 8;
                sb.Append(ch);
            }
            for (i = 3; i >= 0; i--)
            {
                if (sb[i] != '\0')
                {
                    break;
                }
                sb.Remove(i, 1);
            }
            return sb.ToString();
        }


    }



}
